{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "import os\n",
    "from scipy import misc\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.utils import shuffle\n",
    "import pickle\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 加载数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def unpickle(file):\n",
    "    import pickle\n",
    "    with open(file, 'rb') as fo:\n",
    "        dict = pickle.load(fo, encoding='bytes')\n",
    "    return dict"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 加载标签"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dict_keys([b'fine_label_names', b'coarse_label_names'])"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "meta=unpickle(\"./cifar-100-python/meta\")\n",
    "meta.keys()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 加载训练集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "trainset=unpickle(\"./cifar-100-python/train\")\n",
    "trainset_x=trainset[b'data']\n",
    "trainset_y=trainset[b'coarse_labels']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "50000"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "n_trainset=len(trainset_x)\n",
    "n_trainset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "20"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "n_class=len(meta[b'coarse_label_names'])\n",
    "n_class"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 加载测试集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "testset=unpickle(\"./cifar-100-python/test\")\n",
    "testset_x=testset[b'data']\n",
    "testset_y=testset[b'coarse_labels']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 将数据集图像数据转成RGB图像"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(50000, 32, 32, 3)"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "trainset_x=trainset_x.reshape(-1,3,32,32)\n",
    "trainset_x=np.rollaxis(trainset_x, 1, 4)\n",
    "trainset_x.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(10000, 32, 32, 3)"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "testset_x=testset_x.reshape(-1,3,32,32)\n",
    "testset_x=np.rollaxis(testset_x, 1, 4)\n",
    "testset_x.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据增强处理函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "import shutil\n",
    "from PIL import Image\n",
    "import sys\n",
    "\n",
    "current_num = 0\n",
    "\n",
    "def CLAHE(img):\n",
    "    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))\n",
    "    cl1 = clahe.apply(img)\n",
    "    return cl1\n",
    "\n",
    "def Histograms_Equalization(img):\n",
    "    equ = cv2.equalizeHist(img)\n",
    "    return equ\n",
    "\n",
    "def make_one_hot(data, num):\n",
    "    return (np.arange(num)==data[:,None]).astype(np.int64)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 处理训练集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " 0 / 50000\r",
      " 1 / 50000\r",
      " 2 / 50000\r",
      " 3 / 50000\r",
      " 4 / 50000\r",
      " 5 / 50000\r",
      " 6 / 50000\r",
      " 7 / 50000\r",
      " 8 / 50000\r",
      " 9 / 50000\r",
      " 10 / 50000\r",
      " 11 / 50000\r",
      " 12 / 50000\r",
      " 13 / 50000\r",
      " 14 / 50000\r",
      " 15 / 50000\r",
      " 16 / 50000\r",
      " 17 / 50000\r",
      " 18 / 50000\r",
      " 19 / 50000\r",
      " 20 / 50000\r",
      " 21 / 50000\r",
      " 22 / 50000\r",
      " 23 / 50000\r",
      " 24 / 50000\r",
      " 25 / 50000\r",
      " 26 / 50000\r",
      " 27 / 50000\r",
      " 28 / 50000\r",
      " 29 / 50000\r",
      " 30 / 50000\r",
      " 31 / 50000\r",
      " 32 / 50000\r",
      " 33 / 50000\r",
      " 34 / 50000\r",
      " 35 / 50000\r",
      " 36 / 50000\r",
      " 37 / 50000\r",
      " 38 / 50000\r",
      " 39 / 50000\r",
      " 40 / 50000\r",
      " 41 / 50000\r",
      " 42 / 50000\r",
      " 43 / 50000\r",
      " 44 / 50000\r",
      " 45 / 50000\r",
      " 46 / 50000\r",
      " 47 / 50000\r",
      " 48 / 50000\r",
      " 49 / 50000\r",
      " 50 / 50000\r",
      " 51 / 50000\r",
      " 52 / 50000\r",
      " 53 / 50000\r",
      " 54 / 50000\r",
      " 55 / 50000\r",
      " 56 / 50000\r",
      " 57 / 50000\r",
      " 58 / 50000\r",
      " 59 / 50000\r",
      " 60 / 50000\r",
      " 61 / 50000\r",
      " 62 / 50000\r",
      " 63 / 50000\r",
      " 64 / 50000\r",
      " 65 / 50000\r",
      " 66 / 50000\r",
      " 67 / 50000\r",
      " 68 / 50000\r",
      " 69 / 50000\r",
      " 70 / 50000\r",
      " 71 / 50000\r",
      " 72 / 50000\r",
      " 73 / 50000\r",
      " 74 / 50000\r",
      " 75 / 50000\r",
      " 76 / 50000\r",
      " 77 / 50000\r",
      " 78 / 50000\r",
      " 79 / 50000\r",
      " 80 / 50000\r",
      " 81 / 50000\r",
      " 82 / 50000\r",
      " 83 / 50000\r",
      " 84 / 50000\r",
      " 85 / 50000\r",
      " 86 / 50000\r",
      " 87 / 50000\r",
      " 88 / 50000\r",
      " 89 / 50000\r",
      " 90 / 50000\r",
      " 91 / 50000\r",
      " 92 / 50000\r",
      " 93 / 50000\r",
      " 94 / 50000\r",
      " 95 / 50000\r",
      " 96 / 50000\r",
      " 97 / 50000\r",
      " 98 / 50000\r",
      " 99 / 50000\r",
      " 100 / 50000\r",
      " 101 / 50000\r",
      " 102 / 50000\r",
      " 103 / 50000\r",
      " 104 / 50000\r",
      " 105 / 50000\r",
      " 106 / 50000\r",
      " 107 / 50000\r",
      " 108 / 50000\r",
      " 109 / 50000\r",
      " 110 / 50000\r",
      " 111 / 50000\r",
      " 112 / 50000\r",
      " 113 / 50000\r",
      " 114 / 50000\r",
      " 115 / 50000\r",
      " 116 / 50000\r",
      " 117 / 50000\r",
      " 118 / 50000\r",
      " 119 / 50000\r",
      " 120 / 50000\r",
      " 121 / 50000\r",
      " 122 / 50000\r",
      " 123 / 50000\r",
      " 124 / 50000\r",
      " 125 / 50000\r",
      " 126 / 50000\r",
      " 127 / 50000\r",
      " 128 / 50000\r",
      " 129 / 50000\r",
      " 130 / 50000\r",
      " 131 / 50000\r",
      " 132 / 50000\r",
      " 133 / 50000\r",
      " 134 / 50000\r",
      " 135 / 50000\r",
      " 136 / 50000\r",
      " 137 / 50000\r",
      " 138 / 50000\r",
      " 139 / 50000\r",
      " 140 / 50000\r",
      " 141 / 50000\r",
      " 142 / 50000\r",
      " 143 / 50000\r",
      " 144 / 50000\r",
      " 145 / 50000\r",
      " 146 / 50000\r",
      " 147 / 50000\r",
      " 148 / 50000\r",
      " 149 / 50000\r",
      " 150 / 50000\r",
      " 151 / 50000\r",
      " 152 / 50000\r",
      " 153 / 50000\r",
      " 154 / 50000\r",
      " 155 / 50000\r",
      " 156 / 50000\r",
      " 157 / 50000\r",
      " 158 / 50000\r",
      " 159 / 50000\r",
      " 160 / 50000\r",
      " 161 / 50000\r",
      " 162 / 50000\r",
      " 163 / 50000\r",
      " 164 / 50000\r",
      " 165 / 50000\r",
      " 166 / 50000\r",
      " 167 / 50000\r",
      " 168 / 50000\r",
      " 169 / 50000\r",
      " 170 / 50000\r",
      " 171 / 50000\r",
      " 172 / 50000\r",
      " 173 / 50000\r",
      " 174 / 50000\r",
      " 175 / 50000\r",
      " 176 / 50000\r",
      " 177 / 50000\r",
      " 178 / 50000\r",
      " 179 / 50000\r",
      " 180 / 50000\r",
      " 181 / 50000\r",
      " 182 / 50000\r",
      " 183 / 50000\r",
      " 184 / 50000\r",
      " 185 / 50000\r",
      " 186 / 50000\r",
      " 187 / 50000\r",
      " 188 / 50000\r",
      " 189 / 50000\r",
      " 190 / 50000\r",
      " 191 / 50000\r",
      " 192 / 50000\r",
      " 193 / 50000\r",
      " 194 / 50000\r",
      " 195 / 50000\r",
      " 196 / 50000\r",
      " 197 / 50000\r",
      " 198 / 50000\r",
      " 199 / 50000\r",
      " 200 / 50000\r",
      " 201 / 50000\r",
      " 202 / 50000\r",
      " 203 / 50000\r",
      " 204 / 50000\r",
      " 205 / 50000\r",
      " 206 / 50000\r",
      " 207 / 50000\r",
      " 208 / 50000\r",
      " 209 / 50000\r",
      " 210 / 50000\r",
      " 211 / 50000\r",
      " 212 / 50000\r",
      " 213 / 50000\r",
      " 214 / 50000\r",
      " 215 / 50000\r",
      " 216 / 50000\r",
      " 217 / 50000\r",
      " 218 / 50000\r",
      " 219 / 50000\r",
      " 220 / 50000\r",
      " 221 / 50000\r",
      " 222 / 50000\r",
      " 223 / 50000\r",
      " 224 / 50000\r",
      " 225 / 50000\r",
      " 226 / 50000\r",
      " 227 / 50000\r",
      " 228 / 50000\r",
      " 229 / 50000\r",
      " 230 / 50000\r",
      " 231 / 50000\r",
      " 232 / 50000\r",
      " 233 / 50000\r",
      " 234 / 50000\r",
      " 235 / 50000\r",
      " 236 / 50000\r",
      " 237 / 50000\r",
      " 238 / 50000\r",
      " 239 / 50000\r",
      " 240 / 50000\r",
      " 241 / 50000\r",
      " 242 / 50000\r",
      " 243 / 50000\r",
      " 244 / 50000\r",
      " 245 / 50000\r",
      " 246 / 50000\r",
      " 247 / 50000\r",
      " 248 / 50000\r",
      " 249 / 50000\r",
      " 250 / 50000\r",
      " 251 / 50000\r",
      " 252 / 50000\r",
      " 253 / 50000\r",
      " 254 / 50000\r",
      " 255 / 50000\r",
      " 256 / 50000\r",
      " 257 / 50000\r",
      " 258 / 50000\r",
      " 259 / 50000\r",
      " 260 / 50000\r",
      " 261 / 50000\r",
      " 262 / 50000\r",
      " 263 / 50000\r",
      " 264 / 50000\r",
      " 265 / 50000\r",
      " 266 / 50000\r",
      " 267 / 50000\r",
      " 268 / 50000\r",
      " 269 / 50000\r",
      " 270 / 50000\r",
      " 271 / 50000\r",
      " 272 / 50000\r",
      " 273 / 50000\r",
      " 274 / 50000\r",
      " 275 / 50000\r",
      " 276 / 50000\r",
      " 277 / 50000\r",
      " 278 / 50000\r",
      " 279 / 50000\r",
      " 280 / 50000\r",
      " 281 / 50000\r",
      " 282 / 50000\r",
      " 283 / 50000\r",
      " 284 / 50000\r",
      " 285 / 50000\r",
      " 286 / 50000\r",
      " 287 / 50000\r",
      " 288 / 50000\r",
      " 289 / 50000\r",
      " 290 / 50000\r",
      " 291 / 50000\r",
      " 292 / 50000\r",
      " 293 / 50000\r",
      " 294 / 50000\r",
      " 295 / 50000\r",
      " 296 / 50000\r",
      " 297 / 50000\r",
      " 298 / 50000\r",
      " 299 / 50000\r",
      " 300 / 50000\r",
      " 301 / 50000\r",
      " 302 / 50000\r",
      " 303 / 50000\r",
      " 304 / 50000\r",
      " 305 / 50000\r",
      " 306 / 50000\r",
      " 307 / 50000\r",
      " 308 / 50000\r",
      " 309 / 50000\r",
      " 310 / 50000\r",
      " 311 / 50000\r",
      " 312 / 50000\r",
      " 313 / 50000\r",
      " 314 / 50000\r",
      " 315 / 50000\r",
      " 316 / 50000\r",
      " 317 / 50000\r",
      " 318 / 50000\r",
      " 319 / 50000\r",
      " 320 / 50000\r",
      " 321 / 50000\r",
      " 322 / 50000\r",
      " 323 / 50000\r",
      " 324 / 50000\r",
      " 325 / 50000\r",
      " 326 / 50000\r",
      " 327 / 50000\r",
      " 328 / 50000\r",
      " 329 / 50000\r",
      " 330 / 50000\r",
      " 331 / 50000\r",
      " 332 / 50000\r",
      " 333 / 50000\r",
      " 334 / 50000\r",
      " 335 / 50000\r",
      " 336 / 50000\r",
      " 337 / 50000\r",
      " 338 / 50000\r",
      " 339 / 50000\r",
      " 340 / 50000\r",
      " 341 / 50000\r",
      " 342 / 50000\r",
      " 343 / 50000\r",
      " 344 / 50000\r",
      " 345 / 50000\r",
      " 346 / 50000\r",
      " 347 / 50000\r",
      " 348 / 50000\r",
      " 349 / 50000\r",
      " 350 / 50000\r",
      " 351 / 50000\r",
      " 352 / 50000\r",
      " 353 / 50000\r",
      " 354 / 50000\r",
      " 355 / 50000\r",
      " 356 / 50000\r",
      " 357 / 50000\r",
      " 358 / 50000\r",
      " 359 / 50000\r",
      " 360 / 50000\r",
      " 361 / 50000\r",
      " 362 / 50000\r",
      " 363 / 50000\r",
      " 364 / 50000\r",
      " 365 / 50000\r",
      " 366 / 50000\r",
      " 367 / 50000\r",
      " 368 / 50000\r",
      " 369 / 50000\r",
      " 370 / 50000\r",
      " 371 / 50000\r",
      " 372 / 50000\r",
      " 373 / 50000\r",
      " 374 / 50000\r",
      " 375 / 50000\r",
      " 376 / 50000\r",
      " 377 / 50000\r",
      " 378 / 50000\r",
      " 379 / 50000\r",
      " 380 / 50000\r",
      " 381 / 50000\r",
      " 382 / 50000\r",
      " 383 / 50000\r",
      " 384 / 50000\r",
      " 385 / 50000\r",
      " 386 / 50000\r",
      " 387 / 50000\r",
      " 388 / 50000\r",
      " 389 / 50000\r",
      " 390 / 50000\r",
      " 391 / 50000\r",
      " 392 / 50000\r",
      " 393 / 50000\r",
      " 394 / 50000\r",
      " 395 / 50000\r",
      " 396 / 50000\r",
      " 397 / 50000\r",
      " 398 / 50000\r",
      " 399 / 50000\r",
      " 400 / 50000\r",
      " 401 / 50000\r",
      " 402 / 50000\r",
      " 403 / 50000\r",
      " 404 / 50000\r",
      " 405 / 50000\r",
      " 406 / 50000\r",
      " 407 / 50000\r",
      " 408 / 50000\r",
      " 409 / 50000\r",
      " 410 / 50000\r",
      " 411 / 50000\r",
      " 412 / 50000\r",
      " 413 / 50000\r",
      " 414 / 50000\r",
      " 415 / 50000\r",
      " 416 / 50000\r",
      " 417 / 50000\r",
      " 418 / 50000\r",
      " 419 / 50000\r",
      " 420 / 50000\r",
      " 421 / 50000\r",
      " 422 / 50000\r",
      " 423 / 50000\r",
      " 424 / 50000\r",
      " 425 / 50000\r",
      " 426 / 50000\r",
      " 427 / 50000\r",
      " 428 / 50000\r",
      " 429 / 50000\r",
      " 430 / 50000\r",
      " 431 / 50000\r",
      " 432 / 50000\r",
      " 433 / 50000\r",
      " 434 / 50000\r",
      " 435 / 50000\r",
      " 436 / 50000\r",
      " 437 / 50000\r",
      " 438 / 50000\r",
      " 439 / 50000\r",
      " 440 / 50000\r",
      " 441 / 50000\r",
      " 442 / 50000\r",
      " 443 / 50000\r",
      " 444 / 50000\r",
      " 445 / 50000\r",
      " 446 / 50000\r",
      " 447 / 50000\r",
      " 448 / 50000\r",
      " 449 / 50000\r",
      " 450 / 50000\r",
      " 451 / 50000\r",
      " 452 / 50000\r",
      " 453 / 50000\r",
      " 454 / 50000\r",
      " 455 / 50000\r",
      " 456 / 50000\r",
      " 457 / 50000\r",
      " 458 / 50000\r",
      " 459 / 50000\r",
      " 460 / 50000\r",
      " 461 / 50000\r",
      " 462 / 50000\r",
      " 463 / 50000\r",
      " 464 / 50000\r",
      " 465 / 50000\r",
      " 466 / 50000\r",
      " 467 / 50000\r",
      " 468 / 50000\r",
      " 469 / 50000\r",
      " 470 / 50000\r",
      " 471 / 50000\r",
      " 472 / 50000\r",
      " 473 / 50000\r",
      " 474 / 50000\r",
      " 475 / 50000\r",
      " 476 / 50000\r",
      " 477 / 50000\r",
      " 478 / 50000\r",
      " 479 / 50000\r",
      " 480 / 50000\r",
      " 481 / 50000\r",
      " 482 / 50000\r",
      " 483 / 50000\r",
      " 484 / 50000\r",
      " 485 / 50000\r",
      " 486 / 50000\r",
      " 487 / 50000\r",
      " 488 / 50000\r",
      " 489 / 50000\r",
      " 490 / 50000\r",
      " 491 / 50000\r",
      " 492 / 50000\r",
      " 493 / 50000\r",
      " 494 / 50000\r",
      " 495 / 50000\r",
      " 496 / 50000\r",
      " 497 / 50000\r",
      " 498 / 50000\r",
      " 499 / 50000\r",
      " 500 / 50000\r",
      " 501 / 50000\r",
      " 502 / 50000\r",
      " 503 / 50000\r",
      " 504 / 50000\r",
      " 505 / 50000\r",
      " 506 / 50000\r",
      " 507 / 50000\r",
      " 508 / 50000\r",
      " 509 / 50000\r",
      " 510 / 50000\r",
      " 511 / 50000\r",
      " 512 / 50000\r",
      " 513 / 50000\r",
      " 514 / 50000\r",
      " 515 / 50000\r",
      " 516 / 50000\r",
      " 517 / 50000\r",
      " 518 / 50000\r",
      " 519 / 50000\r",
      " 520 / 50000\r",
      " 521 / 50000\r",
      " 522 / 50000\r",
      " 523 / 50000\r",
      " 524 / 50000\r",
      " 525 / 50000\r",
      " 526 / 50000\r",
      " 527 / 50000\r",
      " 528 / 50000\r",
      " 529 / 50000\r",
      " 530 / 50000\r",
      " 531 / 50000\r",
      " 532 / 50000\r",
      " 533 / 50000\r",
      " 534 / 50000\r",
      " 535 / 50000\r",
      " 536 / 50000\r",
      " 537 / 50000\r",
      " 538 / 50000\r",
      " 539 / 50000\r",
      " 540 / 50000\r",
      " 541 / 50000\r",
      " 542 / 50000\r",
      " 543 / 50000\r",
      " 544 / 50000\r",
      " 545 / 50000\r",
      " 546 / 50000\r",
      " 547 / 50000\r",
      " 548 / 50000\r",
      " 549 / 50000\r",
      " 550 / 50000\r",
      " 551 / 50000\r",
      " 552 / 50000\r",
      " 553 / 50000\r",
      " 554 / 50000\r",
      " 555 / 50000\r",
      " 556 / 50000\r",
      " 557 / 50000\r",
      " 558 / 50000\r",
      " 559 / 50000\r",
      " 560 / 50000\r",
      " 561 / 50000\r",
      " 562 / 50000\r",
      " 563 / 50000\r",
      " 564 / 50000\r",
      " 565 / 50000\r",
      " 566 / 50000\r",
      " 567 / 50000\r",
      " 568 / 50000\r",
      " 569 / 50000\r",
      " 570 / 50000\r",
      " 571 / 50000\r",
      " 572 / 50000\r",
      " 573 / 50000\r",
      " 574 / 50000\r",
      " 575 / 50000\r",
      " 576 / 50000\r",
      " 577 / 50000\r",
      " 578 / 50000\r",
      " 579 / 50000\r",
      " 580 / 50000\r",
      " 581 / 50000\r",
      " 582 / 50000\r",
      " 583 / 50000\r",
      " 584 / 50000\r",
      " 585 / 50000\r",
      " 586 / 50000\r",
      " 587 / 50000\r",
      " 588 / 50000\r",
      " 589 / 50000\r",
      " 590 / 50000\r",
      " 591 / 50000\r",
      " 592 / 50000\r",
      " 593 / 50000\r",
      " 594 / 50000\r",
      " 595 / 50000\r",
      " 596 / 50000\r",
      " 597 / 50000\r",
      " 598 / 50000\r",
      " 599 / 50000\r",
      " 600 / 50000\r",
      " 601 / 50000\r",
      " 602 / 50000\r",
      " 603 / 50000\r",
      " 604 / 50000\r",
      " 605 / 50000\r",
      " 606 / 50000\r",
      " 607 / 50000\r",
      " 608 / 50000\r",
      " 609 / 50000\r",
      " 610 / 50000\r",
      " 611 / 50000\r",
      " 612 / 50000\r",
      " 613 / 50000\r",
      " 614 / 50000\r",
      " 615 / 50000\r",
      " 616 / 50000\r",
      " 617 / 50000\r",
      " 618 / 50000\r",
      " 619 / 50000\r",
      " 620 / 50000\r",
      " 621 / 50000\r",
      " 622 / 50000\r",
      " 623 / 50000\r",
      " 624 / 50000\r",
      " 625 / 50000\r",
      " 626 / 50000\r",
      " 627 / 50000\r",
      " 628 / 50000\r",
      " 629 / 50000\r",
      " 630 / 50000\r",
      " 631 / 50000\r",
      " 632 / 50000\r",
      " 633 / 50000\r",
      " 634 / 50000\r",
      " 635 / 50000\r",
      " 636 / 50000\r",
      " 637 / 50000\r",
      " 638 / 50000\r",
      " 639 / 50000\r",
      " 640 / 50000\r",
      " 641 / 50000\r",
      " 642 / 50000\r",
      " 643 / 50000\r",
      " 644 / 50000\r",
      " 645 / 50000\r",
      " 646 / 50000\r",
      " 647 / 50000\r"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " 648 / 50000\r",
      " 649 / 50000\r",
      " 650 / 50000\r",
      " 651 / 50000\r",
      " 652 / 50000\r",
      " 653 / 50000\r",
      " 654 / 50000\r",
      " 655 / 50000\r",
      " 656 / 50000\r",
      " 657 / 50000\r",
      " 658 / 50000\r",
      " 659 / 50000\r",
      " 660 / 50000\r",
      " 661 / 50000\r",
      " 662 / 50000\r",
      " 663 / 50000\r",
      " 664 / 50000\r",
      " 665 / 50000\r",
      " 666 / 50000\r",
      " 667 / 50000\r",
      " 668 / 50000\r",
      " 669 / 50000\r",
      " 670 / 50000\r",
      " 671 / 50000\r",
      " 672 / 50000\r",
      " 673 / 50000\r",
      " 674 / 50000\r",
      " 675 / 50000\r",
      " 676 / 50000\r",
      " 677 / 50000\r",
      " 678 / 50000\r",
      " 679 / 50000\r",
      " 680 / 50000\r",
      " 681 / 50000\r",
      " 682 / 50000\r",
      " 683 / 50000\r",
      " 684 / 50000\r",
      " 685 / 50000\r",
      " 686 / 50000\r",
      " 687 / 50000\r",
      " 688 / 50000\r",
      " 689 / 50000\r",
      " 690 / 50000\r",
      " 691 / 50000\r",
      " 692 / 50000\r",
      " 693 / 50000\r",
      " 694 / 50000\r",
      " 695 / 50000\r",
      " 696 / 50000\r",
      " 697 / 50000\r",
      " 698 / 50000\r",
      " 699 / 50000\r",
      " 700 / 50000\r",
      " 701 / 50000\r",
      " 702 / 50000\r",
      " 703 / 50000\r",
      " 704 / 50000\r",
      " 705 / 50000\r",
      " 706 / 50000\r",
      " 707 / 50000\r",
      " 708 / 50000\r",
      " 709 / 50000\r",
      " 710 / 50000\r",
      " 711 / 50000\r",
      " 712 / 50000\r",
      " 713 / 50000\r",
      " 714 / 50000\r",
      " 715 / 50000\r",
      " 716 / 50000\r",
      " 717 / 50000\r",
      " 718 / 50000\r",
      " 719 / 50000\r",
      " 720 / 50000\r",
      " 721 / 50000\r",
      " 722 / 50000\r",
      " 723 / 50000\r",
      " 724 / 50000\r",
      " 725 / 50000\r",
      " 726 / 50000\r",
      " 727 / 50000\r",
      " 728 / 50000\r",
      " 729 / 50000\r",
      " 730 / 50000\r",
      " 731 / 50000\r",
      " 732 / 50000\r",
      " 733 / 50000\r",
      " 734 / 50000\r",
      " 735 / 50000\r",
      " 736 / 50000\r",
      " 737 / 50000\r",
      " 738 / 50000\r",
      " 739 / 50000\r",
      " 740 / 50000\r",
      " 741 / 50000\r",
      " 742 / 50000\r",
      " 743 / 50000\r",
      " 744 / 50000\r",
      " 745 / 50000\r",
      " 746 / 50000\r",
      " 747 / 50000\r",
      " 748 / 50000\r",
      " 749 / 50000\r",
      " 750 / 50000\r",
      " 751 / 50000\r",
      " 752 / 50000\r",
      " 753 / 50000\r",
      " 754 / 50000\r",
      " 755 / 50000\r",
      " 756 / 50000\r",
      " 757 / 50000\r",
      " 758 / 50000\r",
      " 759 / 50000\r",
      " 760 / 50000\r",
      " 761 / 50000\r",
      " 762 / 50000\r",
      " 763 / 50000\r",
      " 764 / 50000\r",
      " 765 / 50000\r",
      " 766 / 50000\r",
      " 767 / 50000\r",
      " 768 / 50000\r",
      " 769 / 50000\r",
      " 770 / 50000\r",
      " 771 / 50000\r",
      " 772 / 50000\r",
      " 773 / 50000\r",
      " 774 / 50000\r",
      " 775 / 50000\r",
      " 776 / 50000\r",
      " 777 / 50000\r",
      " 778 / 50000\r",
      " 779 / 50000\r",
      " 780 / 50000\r",
      " 781 / 50000\r",
      " 782 / 50000\r",
      " 783 / 50000\r",
      " 784 / 50000\r",
      " 785 / 50000\r",
      " 786 / 50000\r",
      " 787 / 50000\r",
      " 788 / 50000\r",
      " 789 / 50000\r",
      " 790 / 50000\r",
      " 791 / 50000\r",
      " 792 / 50000\r",
      " 793 / 50000\r",
      " 794 / 50000\r",
      " 795 / 50000\r",
      " 796 / 50000\r",
      " 797 / 50000\r",
      " 798 / 50000\r",
      " 799 / 50000\r",
      " 800 / 50000\r",
      " 801 / 50000\r",
      " 802 / 50000\r",
      " 803 / 50000\r",
      " 804 / 50000\r",
      " 805 / 50000\r",
      " 806 / 50000\r",
      " 807 / 50000\r",
      " 808 / 50000\r",
      " 809 / 50000\r",
      " 810 / 50000\r",
      " 811 / 50000\r",
      " 812 / 50000\r",
      " 813 / 50000\r",
      " 814 / 50000\r",
      " 815 / 50000\r",
      " 816 / 50000\r",
      " 817 / 50000\r",
      " 818 / 50000\r",
      " 819 / 50000\r",
      " 820 / 50000\r",
      " 821 / 50000\r",
      " 822 / 50000\r",
      " 823 / 50000\r",
      " 824 / 50000\r",
      " 825 / 50000\r",
      " 826 / 50000\r",
      " 827 / 50000\r",
      " 828 / 50000\r",
      " 829 / 50000\r",
      " 830 / 50000\r",
      " 831 / 50000\r",
      " 832 / 50000\r",
      " 833 / 50000\r",
      " 834 / 50000\r",
      " 835 / 50000\r",
      " 836 / 50000\r",
      " 837 / 50000\r",
      " 838 / 50000\r",
      " 839 / 50000\r",
      " 840 / 50000\r",
      " 841 / 50000\r",
      " 842 / 50000\r",
      " 843 / 50000\r",
      " 844 / 50000\r",
      " 845 / 50000\r",
      " 846 / 50000\r",
      " 847 / 50000\r",
      " 848 / 50000\r",
      " 849 / 50000\r",
      " 850 / 50000\r",
      " 851 / 50000\r",
      " 852 / 50000\r",
      " 853 / 50000\r",
      " 854 / 50000\r",
      " 855 / 50000\r",
      " 856 / 50000\r",
      " 857 / 50000\r",
      " 858 / 50000\r",
      " 859 / 50000\r",
      " 860 / 50000\r",
      " 861 / 50000\r",
      " 862 / 50000\r",
      " 863 / 50000\r",
      " 864 / 50000\r",
      " 865 / 50000\r",
      " 866 / 50000\r",
      " 867 / 50000\r",
      " 868 / 50000\r",
      " 869 / 50000\r",
      " 870 / 50000\r",
      " 871 / 50000\r",
      " 872 / 50000\r",
      " 873 / 50000\r",
      " 874 / 50000\r",
      " 875 / 50000\r",
      " 876 / 50000\r",
      " 877 / 50000\r",
      " 878 / 50000\r",
      " 879 / 50000\r",
      " 880 / 50000\r",
      " 881 / 50000\r",
      " 882 / 50000\r",
      " 883 / 50000\r",
      " 884 / 50000\r",
      " 885 / 50000\r",
      " 886 / 50000\r",
      " 887 / 50000\r",
      " 888 / 50000\r",
      " 889 / 50000\r",
      " 890 / 50000\r",
      " 891 / 50000\r",
      " 892 / 50000\r",
      " 893 / 50000\r",
      " 894 / 50000\r",
      " 895 / 50000\r",
      " 896 / 50000\r",
      " 897 / 50000\r",
      " 898 / 50000\r",
      " 899 / 50000\r",
      " 900 / 50000\r",
      " 901 / 50000\r",
      " 902 / 50000\r",
      " 903 / 50000\r",
      " 904 / 50000\r",
      " 905 / 50000\r",
      " 906 / 50000\r",
      " 907 / 50000\r",
      " 908 / 50000\r",
      " 909 / 50000\r",
      " 910 / 50000\r",
      " 911 / 50000\r",
      " 912 / 50000\r",
      " 913 / 50000\r",
      " 914 / 50000\r",
      " 915 / 50000\r",
      " 916 / 50000\r",
      " 917 / 50000\r",
      " 918 / 50000\r",
      " 919 / 50000\r",
      " 920 / 50000\r",
      " 921 / 50000\r",
      " 922 / 50000\r",
      " 923 / 50000\r",
      " 924 / 50000\r",
      " 925 / 50000\r",
      " 926 / 50000\r",
      " 927 / 50000\r",
      " 928 / 50000\r",
      " 929 / 50000\r",
      " 930 / 50000\r",
      " 931 / 50000\r",
      " 932 / 50000\r",
      " 933 / 50000\r",
      " 934 / 50000\r",
      " 935 / 50000\r",
      " 936 / 50000\r",
      " 937 / 50000\r",
      " 938 / 50000\r",
      " 939 / 50000\r",
      " 940 / 50000\r",
      " 941 / 50000\r",
      " 942 / 50000\r",
      " 943 / 50000\r",
      " 944 / 50000\r",
      " 945 / 50000\r",
      " 946 / 50000\r",
      " 947 / 50000\r",
      " 948 / 50000\r",
      " 949 / 50000\r",
      " 950 / 50000\r",
      " 951 / 50000\r",
      " 952 / 50000\r",
      " 953 / 50000\r",
      " 954 / 50000\r",
      " 955 / 50000\r",
      " 956 / 50000\r",
      " 957 / 50000\r",
      " 958 / 50000\r",
      " 959 / 50000\r",
      " 960 / 50000\r",
      " 961 / 50000\r",
      " 962 / 50000\r",
      " 963 / 50000\r",
      " 964 / 50000\r",
      " 965 / 50000\r",
      " 966 / 50000\r",
      " 967 / 50000\r",
      " 968 / 50000\r",
      " 969 / 50000\r",
      " 970 / 50000\r",
      " 971 / 50000\r",
      " 972 / 50000\r",
      " 973 / 50000\r",
      " 974 / 50000\r",
      " 975 / 50000\r",
      " 976 / 50000\r",
      " 977 / 50000\r",
      " 978 / 50000\r",
      " 979 / 50000\r",
      " 980 / 50000\r",
      " 981 / 50000\r",
      " 982 / 50000\r",
      " 983 / 50000\r",
      " 984 / 50000\r",
      " 985 / 50000\r",
      " 986 / 50000\r",
      " 987 / 50000\r",
      " 988 / 50000\r",
      " 989 / 50000\r",
      " 990 / 50000\r",
      " 991 / 50000\r",
      " 992 / 50000\r",
      " 993 / 50000\r",
      " 994 / 50000\r",
      " 995 / 50000\r",
      " 996 / 50000\r",
      " 997 / 50000\r",
      " 998 / 50000\r",
      " 999 / 50000\r",
      " 1000 / 50000\r",
      " 1001 / 50000\r",
      " 1002 / 50000\r",
      " 1003 / 50000\r",
      " 1004 / 50000\r",
      " 1005 / 50000\r",
      " 1006 / 50000\r",
      " 1007 / 50000\r",
      " 1008 / 50000\r",
      " 1009 / 50000\r",
      " 1010 / 50000\r",
      " 1011 / 50000\r",
      " 1012 / 50000\r",
      " 1013 / 50000\r",
      " 1014 / 50000\r",
      " 1015 / 50000\r",
      " 1016 / 50000\r",
      " 1017 / 50000\r",
      " 1018 / 50000\r",
      " 1019 / 50000\r",
      " 1020 / 50000\r",
      " 1021 / 50000\r",
      " 1022 / 50000\r",
      " 1023 / 50000\r",
      " 1024 / 50000\r",
      " 1025 / 50000\r",
      " 1026 / 50000\r",
      " 1027 / 50000\r",
      " 1028 / 50000\r",
      " 1029 / 50000\r",
      " 1030 / 50000\r",
      " 1031 / 50000\r",
      " 1032 / 50000\r",
      " 1033 / 50000\r",
      " 1034 / 50000\r",
      " 1035 / 50000\r",
      " 1036 / 50000\r",
      " 1037 / 50000\r",
      " 1038 / 50000\r",
      " 1039 / 50000\r",
      " 1040 / 50000\r",
      " 1041 / 50000\r",
      " 1042 / 50000\r",
      " 1043 / 50000\r",
      " 1044 / 50000\r",
      " 1045 / 50000\r",
      " 1046 / 50000\r",
      " 1047 / 50000\r",
      " 1048 / 50000\r",
      " 1049 / 50000\r",
      " 1050 / 50000\r",
      " 1051 / 50000\r",
      " 1052 / 50000\r",
      " 1053 / 50000\r",
      " 1054 / 50000\r",
      " 1055 / 50000\r",
      " 1056 / 50000\r",
      " 1057 / 50000\r",
      " 1058 / 50000\r",
      " 1059 / 50000\r",
      " 1060 / 50000\r",
      " 1061 / 50000\r",
      " 1062 / 50000\r",
      " 1063 / 50000\r",
      " 1064 / 50000\r",
      " 1065 / 50000\r",
      " 1066 / 50000\r",
      " 1067 / 50000\r",
      " 1068 / 50000\r",
      " 1069 / 50000\r",
      " 1070 / 50000\r",
      " 1071 / 50000\r",
      " 1072 / 50000\r",
      " 1073 / 50000\r",
      " 1074 / 50000\r",
      " 1075 / 50000\r",
      " 1076 / 50000\r",
      " 1077 / 50000\r",
      " 1078 / 50000\r",
      " 1079 / 50000\r",
      " 1080 / 50000\r",
      " 1081 / 50000\r",
      " 1082 / 50000\r",
      " 1083 / 50000\r",
      " 1084 / 50000\r",
      " 1085 / 50000\r",
      " 1086 / 50000\r",
      " 1087 / 50000\r",
      " 1088 / 50000\r",
      " 1089 / 50000\r",
      " 1090 / 50000\r",
      " 1091 / 50000\r",
      " 1092 / 50000\r",
      " 1093 / 50000\r",
      " 1094 / 50000\r",
      " 1095 / 50000\r",
      " 1096 / 50000\r",
      " 1097 / 50000\r",
      " 1098 / 50000\r",
      " 1099 / 50000\r",
      " 1100 / 50000\r",
      " 1101 / 50000\r",
      " 1102 / 50000\r",
      " 1103 / 50000\r",
      " 1104 / 50000\r",
      " 1105 / 50000\r",
      " 1106 / 50000\r",
      " 1107 / 50000\r",
      " 1108 / 50000\r",
      " 1109 / 50000\r",
      " 1110 / 50000\r",
      " 1111 / 50000\r",
      " 1112 / 50000\r",
      " 1113 / 50000\r",
      " 1114 / 50000\r",
      " 1115 / 50000\r",
      " 1116 / 50000\r",
      " 1117 / 50000\r",
      " 1118 / 50000\r",
      " 1119 / 50000\r",
      " 1120 / 50000\r",
      " 1121 / 50000\r",
      " 1122 / 50000\r",
      " 1123 / 50000\r",
      " 1124 / 50000\r",
      " 1125 / 50000\r",
      " 1126 / 50000\r",
      " 1127 / 50000\r",
      " 1128 / 50000\r",
      " 1129 / 50000\r",
      " 1130 / 50000\r",
      " 1131 / 50000\r",
      " 1132 / 50000\r",
      " 1133 / 50000\r",
      " 1134 / 50000\r",
      " 1135 / 50000\r",
      " 1136 / 50000\r",
      " 1137 / 50000\r",
      " 1138 / 50000\r",
      " 1139 / 50000\r",
      " 1140 / 50000\r",
      " 1141 / 50000\r",
      " 1142 / 50000\r",
      " 1143 / 50000\r",
      " 1144 / 50000\r",
      " 1145 / 50000\r",
      " 1146 / 50000\r",
      " 1147 / 50000\r",
      " 1148 / 50000\r",
      " 1149 / 50000\r",
      " 1150 / 50000\r",
      " 1151 / 50000\r",
      " 1152 / 50000\r",
      " 1153 / 50000\r",
      " 1154 / 50000\r",
      " 1155 / 50000\r",
      " 1156 / 50000\r",
      " 1157 / 50000\r",
      " 1158 / 50000\r",
      " 1159 / 50000\r",
      " 1160 / 50000\r",
      " 1161 / 50000\r",
      " 1162 / 50000\r",
      " 1163 / 50000\r",
      " 1164 / 50000\r",
      " 1165 / 50000\r",
      " 1166 / 50000\r",
      " 1167 / 50000\r",
      " 1168 / 50000\r",
      " 1169 / 50000\r",
      " 1170 / 50000\r",
      " 1171 / 50000\r",
      " 1172 / 50000\r",
      " 1173 / 50000\r",
      " 1174 / 50000\r",
      " 1175 / 50000\r",
      " 1176 / 50000\r",
      " 1177 / 50000\r",
      " 1178 / 50000\r",
      " 1179 / 50000\r",
      " 1180 / 50000\r",
      " 1181 / 50000\r",
      " 1182 / 50000\r",
      " 1183 / 50000\r",
      " 1184 / 50000\r",
      " 1185 / 50000\r",
      " 1186 / 50000\r",
      " 1187 / 50000\r",
      " 1188 / 50000\r",
      " 1189 / 50000\r",
      " 1190 / 50000\r",
      " 1191 / 50000\r",
      " 1192 / 50000\r",
      " 1193 / 50000\r",
      " 1194 / 50000\r",
      " 1195 / 50000\r",
      " 1196 / 50000\r",
      " 1197 / 50000\r",
      " 1198 / 50000\r",
      " 1199 / 50000\r",
      " 1200 / 50000\r",
      " 1201 / 50000\r",
      " 1202 / 50000\r",
      " 1203 / 50000\r",
      " 1204 / 50000\r",
      " 1205 / 50000\r",
      " 1206 / 50000\r",
      " 1207 / 50000\r",
      " 1208 / 50000\r",
      " 1209 / 50000\r",
      " 1210 / 50000\r",
      " 1211 / 50000\r",
      " 1212 / 50000\r",
      " 1213 / 50000\r",
      " 1214 / 50000\r",
      " 1215 / 50000\r",
      " 1216 / 50000\r",
      " 1217 / 50000\r",
      " 1218 / 50000\r",
      " 1219 / 50000\r",
      " 1220 / 50000\r",
      " 1221 / 50000\r",
      " 1222 / 50000\r",
      " 1223 / 50000\r",
      " 1224 / 50000\r",
      " 1225 / 50000\r",
      " 1226 / 50000\r",
      " 1227 / 50000\r",
      " 1228 / 50000\r",
      " 1229 / 50000\r",
      " 1230 / 50000\r",
      " 1231 / 50000\r",
      " 1232 / 50000\r",
      " 1233 / 50000\r",
      " 1234 / 50000\r",
      " 1235 / 50000\r",
      " 1236 / 50000\r",
      " 1237 / 50000\r",
      " 1238 / 50000\r",
      " 1239 / 50000\r",
      " 1240 / 50000\r",
      " 1241 / 50000\r",
      " 1242 / 50000\r",
      " 1243 / 50000\r",
      " 1244 / 50000\r",
      " 1245 / 50000\r",
      " 1246 / 50000\r",
      " 1247 / 50000\r",
      " 1248 / 50000\r",
      " 1249 / 50000\r",
      " 1250 / 50000\r",
      " 1251 / 50000\r",
      " 1252 / 50000\r",
      " 1253 / 50000\r",
      " 1254 / 50000\r",
      " 1255 / 50000\r",
      " 1256 / 50000\r",
      " 1257 / 50000\r",
      " 1258 / 50000\r",
      " 1259 / 50000\r",
      " 1260 / 50000\r",
      " 1261 / 50000\r",
      " 1262 / 50000\r",
      " 1263 / 50000\r",
      " 1264 / 50000\r",
      " 1265 / 50000\r",
      " 1266 / 50000\r",
      " 1267 / 50000\r",
      " 1268 / 50000\r",
      " 1269 / 50000\r",
      " 1270 / 50000\r",
      " 1271 / 50000\r",
      " 1272 / 50000\r",
      " 1273 / 50000\r",
      " 1274 / 50000\r",
      " 1275 / 50000\r",
      " 1276 / 50000\r",
      " 1277 / 50000\r",
      " 1278 / 50000\r",
      " 1279 / 50000\r",
      " 1280 / 50000\r",
      " 1281 / 50000\r",
      " 1282 / 50000\r",
      " 1283 / 50000\r",
      " 1284 / 50000\r",
      " 1285 / 50000\r",
      " 1286 / 50000\r",
      " 1287 / 50000\r",
      " 1288 / 50000\r",
      " 1289 / 50000\r",
      " 1290 / 50000\r",
      " 1291 / 50000\r",
      " 1292 / 50000\r",
      " 1293 / 50000\r",
      " 1294 / 50000\r",
      " 1295 / 50000\r",
      " 1296 / 50000\r",
      " 1297 / 50000\r",
      " 1298 / 50000\r",
      " 1299 / 50000\r",
      " 1300 / 50000\r",
      " 1301 / 50000\r",
      " 1302 / 50000\r",
      " 1303 / 50000\r",
      " 1304 / 50000\r",
      " 1305 / 50000\r",
      " 1306 / 50000\r",
      " 1307 / 50000\r",
      " 1308 / 50000\r",
      " 1309 / 50000\r",
      " 1310 / 50000\r",
      " 1311 / 50000\r",
      " 1312 / 50000\r",
      " 1313 / 50000\r",
      " 1314 / 50000\r",
      " 1315 / 50000\r",
      " 1316 / 50000\r",
      " 1317 / 50000\r",
      " 1318 / 50000\r",
      " 1319 / 50000\r",
      " 1320 / 50000\r",
      " 1321 / 50000\r",
      " 1322 / 50000\r",
      " 1323 / 50000\r",
      " 1324 / 50000\r",
      " 1325 / 50000\r",
      " 1326 / 50000\r",
      " 1327 / 50000\r",
      " 1328 / 50000\r",
      " 1329 / 50000\r",
      " 1330 / 50000\r",
      " 1331 / 50000\r",
      " 1332 / 50000\r",
      " 1333 / 50000\r",
      " 1334 / 50000\r",
      " 1335 / 50000\r",
      " 1336 / 50000\r",
      " 1337 / 50000\r",
      " 1338 / 50000\r",
      " 1339 / 50000\r",
      " 1340 / 50000\r",
      " 1341 / 50000\r",
      " 1342 / 50000\r",
      " 1343 / 50000\r",
      " 1344 / 50000\r",
      " 1345 / 50000\r",
      " 1346 / 50000\r",
      " 1347 / 50000\r",
      " 1348 / 50000\r",
      " 1349 / 50000\r",
      " 1350 / 50000\r",
      " 1351 / 50000\r",
      " 1352 / 50000\r",
      " 1353 / 50000\r",
      " 1354 / 50000\r",
      " 1355 / 50000\r",
      " 1356 / 50000\r",
      " 1357 / 50000\r",
      " 1358 / 50000\r",
      " 1359 / 50000\r",
      " 1360 / 50000\r",
      " 1361 / 50000\r",
      " 1362 / 50000\r",
      " 1363 / 50000\r",
      " 1364 / 50000\r",
      " 1365 / 50000\r",
      " 1366 / 50000\r",
      " 1367 / 50000\r",
      " 1368 / 50000\r",
      " 1369 / 50000\r",
      " 1370 / 50000\r",
      " 1371 / 50000\r",
      " 1372 / 50000\r",
      " 1373 / 50000\r",
      " 1374 / 50000\r",
      " 1375 / 50000\r",
      " 1376 / 50000\r",
      " 1377 / 50000\r",
      " 1378 / 50000\r",
      " 1379 / 50000\r",
      " 1380 / 50000\r",
      " 1381 / 50000\r",
      " 1382 / 50000\r",
      " 1383 / 50000\r",
      " 1384 / 50000\r",
      " 1385 / 50000\r",
      " 1386 / 50000\r",
      " 1387 / 50000\r",
      " 1388 / 50000\r",
      " 1389 / 50000\r",
      " 1390 / 50000\r",
      " 1391 / 50000\r",
      " 1392 / 50000\r",
      " 1393 / 50000\r",
      " 1394 / 50000\r",
      " 1395 / 50000\r",
      " 1396 / 50000\r",
      " 1397 / 50000\r",
      " 1398 / 50000\r",
      " 1399 / 50000\r",
      " 1400 / 50000\r",
      " 1401 / 50000\r",
      " 1402 / 50000\r",
      " 1403 / 50000\r",
      " 1404 / 50000\r",
      " 1405 / 50000\r",
      " 1406 / 50000\r",
      " 1407 / 50000\r",
      " 1408 / 50000\r",
      " 1409 / 50000\r",
      " 1410 / 50000\r",
      " 1411 / 50000\r",
      " 1412 / 50000\r",
      " 1413 / 50000\r",
      " 1414 / 50000\r",
      " 1415 / 50000\r",
      " 1416 / 50000\r",
      " 1417 / 50000\r",
      " 1418 / 50000\r",
      " 1419 / 50000\r",
      " 1420 / 50000\r",
      " 1421 / 50000\r",
      " 1422 / 50000\r",
      " 1423 / 50000\r",
      " 1424 / 50000\r",
      " 1425 / 50000\r",
      " 1426 / 50000\r",
      " 1427 / 50000\r"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "All done!50000\n"
     ]
    }
   ],
   "source": [
    "from sklearn.utils import shuffle\n",
    "\n",
    "new_X_train = []\n",
    "new_y_train = []\n",
    "for index in range(n_trainset):\n",
    "    sys.stdout.write(\" {} / {}\\r\".format(index, n_trainset))\n",
    "\n",
    "    img_gray = cv2.cvtColor(trainset_x[index], cv2.COLOR_RGB2GRAY)\n",
    "\n",
    "    new_X_train.append(img_gray.astype('float32') / 255.0)\n",
    "    new_y_train.append(trainset_y[index])\n",
    "    \n",
    "    he_image = Histograms_Equalization(img_gray)\n",
    "    new_X_train.append(he_image.astype('float32') / 255.0)\n",
    "    new_y_train.append(trainset_y[index])\n",
    "    \n",
    "    clahe_img = CLAHE(img_gray)\n",
    "    new_X_train.append(clahe_img.astype('float32') / 255.0)\n",
    "    new_y_train.append(trainset_y[index])\n",
    "    \n",
    "    \n",
    "print(\"All done!\")\n",
    "# all_xs, all_ys = shuffle(np.array(new_X_train), np.array(new_y_train), random_state=0)\n",
    "all_xs = np.expand_dims(new_X_train, 3)\n",
    "all_ys = make_one_hot(np.array(new_y_train), n_class)\n",
    "train_xs, valid_xs, train_ys, valid_ys = train_test_split(\n",
    "    all_xs, all_ys, test_size=0.2, random_state=0)\n",
    "\n",
    "pickle.dump(all_xs, open('all_xs.p', 'wb'))\n",
    "pickle.dump(all_ys, open('all_ys.p', 'wb'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 处理测试集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.utils import shuffle\n",
    "\n",
    "total_batch_size = 64\n",
    "\n",
    "test_set = []\n",
    "for j in range(len(testset_x)):\n",
    "    img_gray = cv2.cvtColor(testset_x[j], cv2.COLOR_RGB2GRAY)\n",
    "#     img_gray = Histograms_Equalization(img_gray)\n",
    "    img_gray = np.expand_dims(img_gray, 2)\n",
    "    img_gray = img_gray / 255.0\n",
    "    test_set.append(img_gray)\n",
    "\n",
    "test_set = np.array(test_set)\n",
    "y_test = make_one_hot(np.array(testset_y), n_class)\n",
    "\n",
    "def get_batches(Xs, ys, batch_size):\n",
    "    for start in range(0, len(Xs), batch_size):\n",
    "        end = min(start + batch_size, len(Xs))\n",
    "        yield Xs[start:end], ys[start:end]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# TensorFlow 2.0实现"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Model Architecture"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### keras basics implementation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "from tensorflow import keras\n",
    "import tensorflow as tf\n",
    "import datetime\n",
    "from tensorflow.python.ops import summary_ops_v2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 第一种模型实现方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 如果在之前的图像预处理部分没有使用img_gray = np.expand_dims(img_gray, 2)的话\n",
    "# 网络一开始的InputLayer可以使用这句代码代替： keras.layers.Reshape(target_shape=[32, 32, 1], input_shape=(32, 32,)),\n",
    "\n",
    "# 另外， InputLayer也可以省略，这样的话， 需要在Conv2D中指定输入的形状，网络前两层（InputLayer和Conv2D）可以用这句代码代替：\n",
    "# keras.layers.Conv2D (kernel_size = (5, 5), filters = 100, activation='relu', input_shape=(32, 32, 1)),\n",
    "\n",
    "# 注意， InputLayer并不是网络的第一层， 只是用来说明输入的尺寸\n",
    "def get_model():\n",
    "    model = keras.Sequential([\n",
    "            keras.layers.InputLayer(input_shape=(32, 32, 1)),\n",
    "            keras.layers.Conv2D (kernel_size = (5, 5), filters = 100, activation='relu'),\n",
    "            keras.layers.MaxPool2D(),\n",
    "            keras.layers.Conv2D (kernel_size = (3, 3), filters = 150, activation='relu'),\n",
    "            keras.layers.MaxPool2D(),\n",
    "            keras.layers.Conv2D (kernel_size = (3, 3), filters = 250, padding='same', activation='relu'),\n",
    "            keras.layers.MaxPool2D(),\n",
    "            keras.layers.Flatten(),\n",
    "            keras.layers.Dense(512, activation='relu'),\n",
    "            keras.layers.Dense(300, activation='relu'),\n",
    "            keras.layers.Dense(n_class, activation='softmax')\n",
    "        ])\n",
    "    return model\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 325,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# 此处代码是判断是否可以使用GPU训练\n",
    "if tf.test.is_gpu_available():\n",
    "    with tf.device(\"GPU:0\"): # Or GPU:1 for the 2nd GPU, GPU:2 for the 3rd etc.\n",
    "        pass\n",
    "    # 下面代码会使用一台机器上的所有GPU进行训练\n",
    "#     strategy = tf.distribute.MirroredStrategy()\n",
    "#     with strategy.scope():"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 如果在数据预处理的部分， 标签没有做one hot编码的话， 这里的损失函数可以使用sparse_categorical_crossentropy\n",
    "model = get_model()\n",
    "model.compile(optimizer=tf.keras.optimizers.Adam(1e-4),\n",
    "              loss='categorical_crossentropy',\n",
    "              metrics=['accuracy'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"sequential\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "conv2d_6 (Conv2D)            (None, 28, 28, 100)       2600      \n",
      "_________________________________________________________________\n",
      "max_pooling2d_6 (MaxPooling2 (None, 14, 14, 100)       0         \n",
      "_________________________________________________________________\n",
      "conv2d_7 (Conv2D)            (None, 12, 12, 150)       135150    \n",
      "_________________________________________________________________\n",
      "max_pooling2d_7 (MaxPooling2 (None, 6, 6, 150)         0         \n",
      "_________________________________________________________________\n",
      "conv2d_8 (Conv2D)            (None, 6, 6, 250)         337750    \n",
      "_________________________________________________________________\n",
      "max_pooling2d_8 (MaxPooling2 (None, 3, 3, 250)         0         \n",
      "_________________________________________________________________\n",
      "flatten_2 (Flatten)          (None, 2250)              0         \n",
      "_________________________________________________________________\n",
      "dense_4 (Dense)              (None, 512)               1152512   \n",
      "_________________________________________________________________\n",
      "dense_5 (Dense)              (None, 300)               153900    \n",
      "_________________________________________________________________\n",
      "dense_6 (Dense)              (None, 20)                6020      \n",
      "=================================================================\n",
      "Total params: 1,787,932\n",
      "Trainable params: 1,787,932\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING: Logging before flag parsing goes to stderr.\n",
      "W0610 11:34:34.541786 4427056576 callbacks.py:859] `period` argument is deprecated. Please use `save_freq` to specify the frequency in number of samples seen.\n"
     ]
    }
   ],
   "source": [
    "checkpoint_path = \"training_models/cp-{epoch:04d}.ckpt\"\n",
    "checkpoint_dir = os.path.dirname(checkpoint_path)\n",
    "\n",
    "cp_callback = tf.keras.callbacks.ModelCheckpoint(\n",
    "    checkpoint_path, verbose=1, save_best_only=True, save_weights_only=True,\n",
    "    # Save weights, every 1-epochs.\n",
    "    period=1)\n",
    "\n",
    "callbacks = [\n",
    "    cp_callback,\n",
    "    # Interrupt training if `val_loss` stops improving for over 2 epochs\n",
    "    tf.keras.callbacks.EarlyStopping(patience=2, monitor='val_loss'),\n",
    "    # Write TensorBoard logs to `./logs` directory\n",
    "    tf.keras.callbacks.TensorBoard(log_dir='./logs')\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "W0610 11:34:46.725752 4427056576 deprecation.py:323] From /Applications/anaconda/envs/tf2beta/lib/python3.6/site-packages/tensorflow/python/ops/math_grad.py:1250: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Use tf.where in 2.0, which has the same broadcast rule as np.where\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 120000 samples, validate on 30000 samples\n",
      "119936/120000 [============================>.] - ETA: 0s - loss: 2.6604 - accuracy: 0.1884\n",
      "Epoch 00001: val_loss improved from inf to 2.41657, saving model to training_models/cp-0001.ckpt\n",
      "120000/120000 [==============================] - 472s 4ms/sample - loss: 2.6603 - accuracy: 0.1884 - val_loss: 2.4166 - val_accuracy: 0.2627\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<tensorflow.python.keras.callbacks.History at 0x1a938adf28>"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 开始训练\n",
    "model.save_weights(checkpoint_path.format(epoch=0))\n",
    "model.fit(train_xs, train_ys, epochs=1, batch_size=64, validation_data=(valid_xs, valid_ys), \n",
    "          callbacks=callbacks) # validation_split=0.2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 在测试集上的准确率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10000/10000 [==============================] - 11s 1ms/sample - loss: 2.4464 - accuracy: 0.2537\n",
      "\n",
      "Test accuracy: 0.2537\n"
     ]
    }
   ],
   "source": [
    "test_loss, test_acc = model.evaluate(test_set, y_test)\n",
    "\n",
    "print('\\nTest accuracy:', test_acc)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 加载保存的参数继续训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 120000 samples, validate on 30000 samples\n",
      "119936/120000 [============================>.] - ETA: 0s - loss: 2.3134 - accuracy: 0.2966\n",
      "Epoch 00001: val_loss improved from 2.41657 to 2.21819, saving model to training_models/cp-0001.ckpt\n",
      "120000/120000 [==============================] - 465s 4ms/sample - loss: 2.3134 - accuracy: 0.2966 - val_loss: 2.2182 - val_accuracy: 0.3215\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<tensorflow.python.keras.callbacks.History at 0x1a79cbdc18>"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "latest = tf.train.latest_checkpoint(checkpoint_dir)\n",
    "\n",
    "model = get_model()\n",
    "\n",
    "model.load_weights(latest)\n",
    "\n",
    "# The re-loaded model needs to be re-compiled.\n",
    "model.compile(optimizer=tf.keras.optimizers.Adam(1e-4),\n",
    "              loss='categorical_crossentropy',\n",
    "              metrics=['accuracy'])\n",
    "\n",
    "model.fit(train_xs, train_ys, epochs=1, batch_size=64, validation_data=(valid_xs, valid_ys), \n",
    "          callbacks=callbacks) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Functional API"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 第二种模型实现方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "inputs = keras.Input(shape=(32, 32, 1))  # Returns an input placeholder\n",
    "\n",
    "# A layer instance is callable on a tensor, and returns a tensor.\n",
    "x = keras.layers.Conv2D (kernel_size = (5, 5), filters = 100, activation='relu')(inputs)\n",
    "x = keras.layers.MaxPool2D()(x)\n",
    "x = keras.layers.Conv2D (kernel_size = (3, 3), filters = 150, activation='relu')(x)\n",
    "x = keras.layers.MaxPool2D()(x)\n",
    "x = keras.layers.Conv2D (kernel_size = (3, 3), filters = 250, padding='same', activation='relu')(x)\n",
    "x = keras.layers.MaxPool2D()(x)\n",
    "x = keras.layers.Flatten()(x)\n",
    "x = keras.layers.Dense(512, activation='relu')(x)\n",
    "x = keras.layers.Dense(300, activation='relu')(x)\n",
    "predictions = keras.layers.Dense(n_class, activation='softmax')(x)\n",
    "\n",
    "model = keras.Model(inputs=inputs, outputs=predictions)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 第三种模型实现方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "class MyModel(keras.Model):\n",
    "\n",
    "    def __init__(self):\n",
    "        super(MyModel, self).__init__(name='my_model')\n",
    "\n",
    "        # Define your layers here.\n",
    "        self.layer1 = keras.layers.Conv2D (kernel_size = (5, 5), filters = 100, activation='relu')\n",
    "        self.layer2 = keras.layers.MaxPool2D()\n",
    "        self.layer3 = keras.layers.Conv2D (kernel_size = (3, 3), filters = 150, activation='relu')\n",
    "        self.layer4 = keras.layers.MaxPool2D()\n",
    "        self.layer5 = keras.layers.Conv2D (kernel_size = (3, 3), filters = 250, padding='same', activation='relu')\n",
    "        self.layer6 = keras.layers.MaxPool2D()\n",
    "        self.layer7 = keras.layers.Flatten()\n",
    "        self.layer8 = keras.layers.Dense(512, activation='relu')\n",
    "        self.layer9 = keras.layers.Dense(300, activation='relu')\n",
    "        self.predictions = keras.layers.Dense(n_class, activation='softmax')\n",
    "\n",
    "    def call(self, inputs):\n",
    "        # Define your forward pass here,\n",
    "        # using layers you previously defined (in `__init__`).\n",
    "        x = self.layer1(inputs)\n",
    "        x = self.layer2(x)\n",
    "        x = self.layer3(x)\n",
    "        x = self.layer4(x)\n",
    "        x = self.layer5(x)\n",
    "        x = self.layer6(x)\n",
    "        x = self.layer7(x)\n",
    "        x = self.layer8(x)\n",
    "        x = self.layer9(x)\n",
    "        predictions = self.predictions(x)\n",
    "\n",
    "        return predictions\n",
    "\n",
    "model = MyModel()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1874/1875 [============================>.] - ETA: 0s - loss: 2.6562 - accuracy: 0.1898\n",
      "Epoch 00001: val_loss did not improve from 2.21819\n",
      "1875/1875 [==============================] - 465s 248ms/step - loss: 2.6560 - accuracy: 0.1899 - val_loss: 2.4274 - val_accuracy: 0.2590\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<tensorflow.python.keras.callbacks.History at 0x1a7a6b5b00>"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 准备数据集开始训练\n",
    "val_dataset = tf.data.Dataset.from_tensor_slices((valid_xs, valid_ys))\n",
    "val_dataset = val_dataset.batch(64).repeat()\n",
    "\n",
    "dataset = tf.data.Dataset.from_tensor_slices((train_xs, train_ys))\n",
    "dataset = dataset.shuffle(128).batch(64).repeat()  # .shuffle(len(train_xs))\n",
    "\n",
    "model.compile(optimizer=tf.keras.optimizers.Adam(1e-4),\n",
    "              loss='categorical_crossentropy',\n",
    "              metrics=['accuracy'])\n",
    "# Don't forget to specify `steps_per_epoch` when calling `fit` on a dataset.\n",
    "model.fit(dataset, epochs=1, steps_per_epoch=(len(train_xs) // total_batch_size), \n",
    "          validation_data=val_dataset, validation_steps=(len(valid_xs) // total_batch_size), callbacks=callbacks)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 用来生成一个图像的输入数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "def generate_x(img):\n",
    "    img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\n",
    "\n",
    "    img_gray = Histograms_Equalization(img)\n",
    "    img_gray = np.expand_dims(img_gray, 2)\n",
    "    img_gray = img_gray / 255.0\n",
    "    img_gray = np.expand_dims(img_gray, 0)\n",
    "    return img_gray"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "def showimg(index):\n",
    "    img_gray = cv2.cvtColor(testset_x[index], cv2.COLOR_RGB2GRAY)\n",
    "    plt.figure()\n",
    "    plt.imshow(img_gray)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 加载模型参数做预测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "14\n",
      "14\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import random\n",
    "latest = tf.train.latest_checkpoint(checkpoint_dir)\n",
    "\n",
    "model = get_model()\n",
    "\n",
    "model.load_weights(latest)\n",
    "\n",
    "index = random.randint(0, len(testset_x))\n",
    "showimg(index)\n",
    "\n",
    "logits = model.predict(generate_x(testset_x[index]).astype('float32'))\n",
    "print(testset_y[index])\n",
    "print(np.argmax(logits[0])) # np.argmax(logits, 0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Functional implementation （Eager Execution Mode）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 学习目标y是one hot独热编码的实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "import datetime\n",
    "from tensorflow import keras\n",
    "from tensorflow.python.ops import summary_ops_v2\n",
    "import time\n",
    "\n",
    "MODEL_DIR = \"./models\"\n",
    "\n",
    "class network(object):\n",
    "    def __init__(self):\n",
    "        # Hyperparameters\n",
    "        self.model = keras.Sequential([\n",
    "            keras.layers.InputLayer(input_shape=(32, 32, 1)),\n",
    "            keras.layers.Conv2D (kernel_size = (5, 5), filters = 100, activation='relu'),\n",
    "            keras.layers.MaxPool2D(),\n",
    "            keras.layers.Conv2D (kernel_size = (3, 3), filters = 150, activation='relu'),\n",
    "            keras.layers.MaxPool2D(),\n",
    "            keras.layers.Conv2D (kernel_size = (3, 3), filters = 250, padding='same', activation='relu'),\n",
    "            keras.layers.MaxPool2D(),\n",
    "            keras.layers.Flatten(),\n",
    "            keras.layers.Dense(512, activation='relu'),\n",
    "            keras.layers.Dense(300, activation='relu'),\n",
    "            keras.layers.Dense(n_class) \n",
    "        ])\n",
    "        self.optimizer = tf.keras.optimizers.Adam(learning_rate=1e-4)\n",
    "\n",
    "        if tf.io.gfile.exists(MODEL_DIR):\n",
    "#             print('Removing existing model dir: {}'.format(MODEL_DIR))\n",
    "#             tf.io.gfile.rmtree(MODEL_DIR)\n",
    "            pass\n",
    "        else:\n",
    "            tf.io.gfile.makedirs(MODEL_DIR)\n",
    "        \n",
    "        train_dir = os.path.join(MODEL_DIR, 'summaries', 'train')\n",
    "        test_dir = os.path.join(MODEL_DIR, 'summaries', 'eval')\n",
    "\n",
    "        self.train_summary_writer = summary_ops_v2.create_file_writer(train_dir, flush_millis=10000)\n",
    "        self.test_summary_writer = summary_ops_v2.create_file_writer(test_dir, flush_millis=10000, name='test')\n",
    "        \n",
    "        checkpoint_dir = os.path.join(MODEL_DIR, 'checkpoints')\n",
    "        self.checkpoint_prefix = os.path.join(checkpoint_dir, 'ckpt')\n",
    "\n",
    "        self.checkpoint = tf.train.Checkpoint(model=self.model, optimizer=self.optimizer)  \n",
    "\n",
    "        # Restore variables on creation if a checkpoint exists.\n",
    "        self.checkpoint.restore(tf.train.latest_checkpoint(checkpoint_dir))\n",
    "    \n",
    "#     @tf.function\n",
    "    def compute_loss(self, logits, labels):\n",
    "        # 如果目标y不是one hot独热编码的话使用sparse_categorical_crossentropy作为损失函数\n",
    "        return tf.reduce_mean(tf.keras.losses.categorical_crossentropy(labels, logits, from_logits=True))\n",
    "\n",
    "\n",
    "    def compute_accuracy(self, logits, labels):\n",
    "        # 注意， 代码中并没有用categorical_accuracy这个函数计算准确率，\n",
    "        # 在后面我们用tf.keras.metrics.CategoricalAccuracy()计算准确率\n",
    "        return tf.keras.metrics.categorical_accuracy(labels, logits)  \n",
    "    \n",
    "    @tf.function\n",
    "    def train_step(self, images, labels):\n",
    "        # Record the operations used to compute the loss, so that the gradient\n",
    "        # of the loss with respect to the variables can be computed.\n",
    "        with tf.GradientTape() as tape:\n",
    "            logits = self.model(images, training=True)\n",
    "            loss = self.compute_loss(logits, labels)\n",
    "            accuracy = self.compute_accuracy(logits, labels)\n",
    "        grads = tape.gradient(loss, self.model.trainable_variables)\n",
    "        self.optimizer.apply_gradients(zip(grads, self.model.trainable_variables))\n",
    "        return loss, accuracy, logits\n",
    "\n",
    "    def training(self, train_dataset, test_dataset, epochs=1, log_freq=50):\n",
    "\n",
    "        for i in range(epochs):\n",
    "            train_start = time.time()\n",
    "            with self.train_summary_writer.as_default():\n",
    "                start = time.time()\n",
    "                # Metrics are stateful. They accumulate values and return a cumulative\n",
    "                # result when you call .result(). Clear accumulated values with .reset_states()\n",
    "                avg_loss = tf.keras.metrics.Mean('loss', dtype=tf.float32)  \n",
    "#                 avg_accuracy = tf.keras.metrics.Mean('accuracy', dtype=tf.float32)  # \n",
    "                avg_accuracy = tf.keras.metrics.CategoricalAccuracy()\n",
    "                \n",
    "                # Datasets can be iterated over like any other Python iterable.\n",
    "                for images, labels in train_dataset:\n",
    "                    loss, accuracy, logits = self.train_step(images, labels)\n",
    "                    avg_loss(loss)\n",
    "#                     avg_accuracy(accuracy)\n",
    "                    avg_accuracy.update_state(labels, logits)\n",
    "                    if tf.equal(self.optimizer.iterations % log_freq, 0):\n",
    "                        summary_ops_v2.scalar('loss', avg_loss.result(), step=self.optimizer.iterations)\n",
    "                        summary_ops_v2.scalar('accuracy', avg_accuracy.result(), step=self.optimizer.iterations)\n",
    "                        \n",
    "                        rate = log_freq / (time.time() - start)\n",
    "                        print('Step #{}\\tLoss: {:0.6f} accuracy: {:0.2f}% ({} steps/sec)'.format(self.optimizer.iterations.numpy(), loss, (avg_accuracy.result() * 100), rate))\n",
    "                        avg_loss.reset_states()\n",
    "                        avg_accuracy.reset_states()\n",
    "                        start = time.time()\n",
    "\n",
    "            train_end = time.time()\n",
    "            print('\\nTrain time for epoch #{} ({} total steps): {}'.format(i + 1, self.optimizer.iterations.numpy(), train_end - train_start))\n",
    "            with self.test_summary_writer.as_default():\n",
    "                self.testing(test_dataset, self.optimizer.iterations)\n",
    "            self.checkpoint.save(self.checkpoint_prefix)\n",
    "        self.export_path = os.path.join(MODEL_DIR, 'export')\n",
    "        tf.saved_model.save(self.model, self.export_path)\n",
    "    \n",
    "    def testing(self, test_dataset, step_num):\n",
    "        \"\"\"Perform an evaluation of `model` on the examples from `dataset`.\"\"\"\n",
    "        avg_loss = tf.keras.metrics.Mean('loss', dtype=tf.float32)\n",
    "#         avg_accuracy = tf.keras.metrics.Mean('accuracy', dtype=tf.float32)\n",
    "        avg_accuracy = tf.keras.metrics.CategoricalAccuracy()\n",
    "\n",
    "        for (images, labels) in test_dataset:\n",
    "            logits = self.model(images, training=False)\n",
    "            avg_loss(self.compute_loss(logits, labels))\n",
    "#             avg_accuracy(self.compute_accuracy(logits, labels))\n",
    "            avg_accuracy.update_state(labels, logits)\n",
    "        print('Model test set loss: {:0.4f} accuracy: {:0.2f}%'.format(avg_loss.result(), avg_accuracy.result() * 100))\n",
    "        summary_ops_v2.scalar('loss', avg_loss.result(), step=step_num)\n",
    "        summary_ops_v2.scalar('accuracy', avg_accuracy.result(), step=step_num)\n",
    "            \n",
    "    def evaluating(self, test_dataset):\n",
    "#         restored_model = tf.saved_model.restore(self.export_path)\n",
    "#         y_predict = restored_model(x_test)\n",
    "        avg_accuracy = tf.keras.metrics.CategoricalAccuracy()\n",
    "\n",
    "        for (images, labels) in test_dataset:\n",
    "            logits = self.model(images, training=False)\n",
    "#             avg_accuracy(self.compute_accuracy(logits, labels))\n",
    "            avg_accuracy.update_state(labels, logits)\n",
    "        print('Model accuracy: {:0.2f}%'.format(avg_accuracy.result() * 100))\n",
    "\n",
    "    def forward(self, xs):  \n",
    "        predictions = self.model(xs)\n",
    "        logits = tf.nn.softmax(predictions)\n",
    "\n",
    "        return logits\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "val_dataset = tf.data.Dataset.from_tensor_slices((valid_xs.astype(np.float32), valid_ys))\n",
    "val_dataset = val_dataset.batch(64)\n",
    "\n",
    "dataset = tf.data.Dataset.from_tensor_slices((train_xs.astype(np.float32), train_ys))\n",
    "dataset = dataset.batch(64)  # .shuffle(len(train_xs))\n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 训练网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Step #50\tLoss: 2.994897 accuracy: 5.66% (3.7079975940959518 steps/sec)\n",
      "Step #100\tLoss: 2.987721 accuracy: 5.03% (4.42650508891934 steps/sec)\n",
      "Step #150\tLoss: 2.956304 accuracy: 7.72% (4.354760733312643 steps/sec)\n",
      "Step #200\tLoss: 2.885026 accuracy: 10.19% (4.316026744254847 steps/sec)\n",
      "Step #250\tLoss: 2.781627 accuracy: 11.38% (4.284291078439908 steps/sec)\n",
      "Step #300\tLoss: 2.930704 accuracy: 12.25% (4.289365782341407 steps/sec)\n",
      "Step #350\tLoss: 2.797307 accuracy: 13.56% (4.282603577072803 steps/sec)\n",
      "Step #400\tLoss: 2.925358 accuracy: 13.19% (4.350552527838406 steps/sec)\n",
      "Step #450\tLoss: 2.844604 accuracy: 15.06% (4.359049298937128 steps/sec)\n",
      "Step #500\tLoss: 2.606718 accuracy: 15.94% (4.381845131242211 steps/sec)\n",
      "Step #550\tLoss: 2.796009 accuracy: 16.03% (4.343087943248135 steps/sec)\n",
      "Step #600\tLoss: 2.769403 accuracy: 15.94% (4.342142758187984 steps/sec)\n",
      "Step #650\tLoss: 2.582366 accuracy: 18.62% (4.383428330341064 steps/sec)\n",
      "Step #700\tLoss: 2.738522 accuracy: 18.19% (4.339460247103693 steps/sec)\n",
      "Step #750\tLoss: 2.522779 accuracy: 19.34% (4.313719133843295 steps/sec)\n",
      "Step #800\tLoss: 2.558491 accuracy: 19.53% (4.4027606268472095 steps/sec)\n",
      "Step #850\tLoss: 2.617172 accuracy: 18.94% (4.387563354061411 steps/sec)\n",
      "Step #900\tLoss: 2.577909 accuracy: 19.06% (4.427407444704433 steps/sec)\n",
      "Step #950\tLoss: 2.417275 accuracy: 20.25% (3.207277057943848 steps/sec)\n",
      "Step #1000\tLoss: 2.417030 accuracy: 21.81% (3.626263087016502 steps/sec)\n",
      "Step #1050\tLoss: 2.487003 accuracy: 21.94% (4.135505302893356 steps/sec)\n",
      "Step #1100\tLoss: 2.705831 accuracy: 21.97% (3.833151797308997 steps/sec)\n",
      "Step #1150\tLoss: 2.568333 accuracy: 22.00% (3.27613832243819 steps/sec)\n",
      "Step #1200\tLoss: 2.746153 accuracy: 23.25% (4.326519761468217 steps/sec)\n",
      "Step #1250\tLoss: 2.468086 accuracy: 22.41% (4.339513854068153 steps/sec)\n",
      "Step #1300\tLoss: 2.653882 accuracy: 23.66% (4.382505803316946 steps/sec)\n",
      "Step #1350\tLoss: 2.489166 accuracy: 22.34% (4.360320408966332 steps/sec)\n",
      "Step #1400\tLoss: 2.446111 accuracy: 24.09% (3.4187315794951942 steps/sec)\n",
      "Step #1450\tLoss: 2.585274 accuracy: 22.81% (3.8303436718085258 steps/sec)\n",
      "Step #1500\tLoss: 2.424048 accuracy: 24.34% (4.360258580978209 steps/sec)\n",
      "Step #1550\tLoss: 2.415994 accuracy: 24.28% (4.415878567382254 steps/sec)\n",
      "Step #1600\tLoss: 2.585299 accuracy: 23.38% (4.026671723354332 steps/sec)\n",
      "Step #1650\tLoss: 2.509738 accuracy: 25.94% (4.414761564263375 steps/sec)\n",
      "Step #1700\tLoss: 2.342165 accuracy: 24.69% (4.388891196767231 steps/sec)\n",
      "Step #1750\tLoss: 2.523353 accuracy: 24.97% (4.214506235640543 steps/sec)\n",
      "Step #1800\tLoss: 2.380554 accuracy: 24.84% (3.4406890513232877 steps/sec)\n",
      "Step #1850\tLoss: 2.445540 accuracy: 24.78% (4.368935689615472 steps/sec)\n",
      "\n",
      "Train time for epoch #1 (1875 total steps): 453.7773127555847\n",
      "Model test set loss: 2.4213 accuracy: 26.07%\n"
     ]
    }
   ],
   "source": [
    "net = network()\n",
    "\n",
    "net.training(dataset, val_dataset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 查看网络在测试集上的准确率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model accuracy: 25.48%\n"
     ]
    }
   ],
   "source": [
    "test_dataset = tf.data.Dataset.from_tensor_slices((test_set.astype(np.float32), y_test))\n",
    "test_dataset = test_dataset.batch(64)\n",
    "net = network()\n",
    "net.evaluating(test_dataset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "scrolled": false
   },
   "source": [
    "## 非one hot版实现"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "此时的label是类别对应的数字，跟上面的实现区别只是损失函数和计算准确率函数不一样，其他都一样，损失函数使用：sparse_categorical_crossentropy，准确率使用sparse_categorical_accuracy计算"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "重新制作数据集，此时不再调用make_one_hot函数将label转换成one hot编码了，剩下的代码跟之前一样"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "All done!50000\n"
     ]
    }
   ],
   "source": [
    "import pickle\n",
    "from sklearn.utils import shuffle\n",
    "\n",
    "new_X_train = []\n",
    "new_y_train = []\n",
    "for index in range(n_trainset):\n",
    "    sys.stdout.write(\" {} / {}\\r\".format(index, n_trainset))\n",
    "\n",
    "    img_gray = cv2.cvtColor(trainset_x[index], cv2.COLOR_RGB2GRAY)\n",
    "\n",
    "    new_X_train.append(img_gray.astype('float32') / 255.0)\n",
    "    new_y_train.append(trainset_y[index])\n",
    "    \n",
    "    he_image = Histograms_Equalization(img_gray)\n",
    "    new_X_train.append(he_image.astype('float32') / 255.0)\n",
    "    new_y_train.append(trainset_y[index])\n",
    "    \n",
    "    clahe_img = CLAHE(img_gray)\n",
    "    new_X_train.append(clahe_img.astype('float32') / 255.0)\n",
    "    new_y_train.append(trainset_y[index])\n",
    "    \n",
    "    \n",
    "\n",
    "# all_xs, all_ys = shuffle(np.array(new_X_train), np.array(new_y_train), random_state=0)\n",
    "all_xs = np.expand_dims(new_X_train, 3)\n",
    "# all_ys = make_one_hot(all_ys, n_class)\n",
    "train_xs, valid_xs, train_ys, valid_ys = train_test_split(\n",
    "    all_xs, np.array(new_y_train), test_size=0.2, random_state=0)\n",
    "\n",
    "# pickle.dump(all_xs, open('all_xs.p', 'wb'))\n",
    "# pickle.dump(all_ys, open('all_ys.p', 'wb'))\n",
    "\n",
    "### Preprocess the data here. It is required to normalize the data. Other preprocessing steps could include \n",
    "### converting to grayscale, etc.\n",
    "### Feel free to use as many code cells as needed.\n",
    "from sklearn.utils import shuffle\n",
    "\n",
    "total_batch_size = 64\n",
    "\n",
    "# # process valid dataset\n",
    "# valid_set = []\n",
    "# for j in range(len(X_valid)):\n",
    "#     img_gray = cv2.cvtColor(X_valid[j], cv2.COLOR_RGB2GRAY)\n",
    "# #     img_gray = Histograms_Equalization(img_gray)\n",
    "#     img_gray = np.expand_dims(img_gray, 2)\n",
    "#     img_gray = img_gray / 255.0\n",
    "#     valid_set.append(img_gray)\n",
    "\n",
    "# valid_set = np.array(valid_set)\n",
    "# # y_valid = make_one_hot(y_valid, n_class)\n",
    "\n",
    "# process test dataset\n",
    "test_set = []\n",
    "for j in range(len(testset_x)):\n",
    "    img_gray = cv2.cvtColor(testset_x[j], cv2.COLOR_RGB2GRAY)\n",
    "#     img_gray = Histograms_Equalization(img_gray)\n",
    "    img_gray = np.expand_dims(img_gray, 2)\n",
    "    img_gray = img_gray / 255.0\n",
    "    test_set.append(img_gray)\n",
    "\n",
    "test_set = np.array(test_set)\n",
    "# y_test = make_one_hot(y_test, n_class)\n",
    "\n",
    "print(\"All done!\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "import datetime\n",
    "from tensorflow import keras\n",
    "from tensorflow.python.ops import summary_ops_v2\n",
    "import time\n",
    "\n",
    "MODEL_DIR = \"./models\"\n",
    "\n",
    "class network(object):\n",
    "    def __init__(self):\n",
    "        # Hyperparameters\n",
    "        self.model = keras.Sequential([\n",
    "            keras.layers.InputLayer(input_shape=(32, 32, 1)),\n",
    "            keras.layers.Conv2D (kernel_size = (5, 5), filters = 100, activation='relu'),\n",
    "            keras.layers.MaxPool2D(),\n",
    "            keras.layers.Conv2D (kernel_size = (3, 3), filters = 150, activation='relu'),\n",
    "            keras.layers.MaxPool2D(),\n",
    "            keras.layers.Conv2D (kernel_size = (3, 3), filters = 250, padding='same', activation='relu'),\n",
    "            keras.layers.MaxPool2D(),\n",
    "            keras.layers.Flatten(),\n",
    "            keras.layers.Dense(512, activation='relu'),\n",
    "            keras.layers.Dense(300, activation='relu'),\n",
    "            keras.layers.Dense(n_class) \n",
    "        ])\n",
    "        self.optimizer = tf.keras.optimizers.Adam(learning_rate=1e-4)\n",
    "\n",
    "        if tf.io.gfile.exists(MODEL_DIR):\n",
    "#             print('Removing existing model dir: {}'.format(MODEL_DIR))\n",
    "#             tf.io.gfile.rmtree(MODEL_DIR)\n",
    "            pass\n",
    "        else:\n",
    "            tf.io.gfile.makedirs(MODEL_DIR)\n",
    "        \n",
    "        train_dir = os.path.join(MODEL_DIR, 'summaries', 'train')\n",
    "        test_dir = os.path.join(MODEL_DIR, 'summaries', 'eval')\n",
    "\n",
    "        self.train_summary_writer = summary_ops_v2.create_file_writer(train_dir, flush_millis=10000)\n",
    "        self.test_summary_writer = summary_ops_v2.create_file_writer(test_dir, flush_millis=10000, name='test')\n",
    "        \n",
    "        checkpoint_dir = os.path.join(MODEL_DIR, 'checkpoints')\n",
    "        self.checkpoint_prefix = os.path.join(checkpoint_dir, 'ckpt')\n",
    "        self.checkpoint = tf.train.Checkpoint(model=self.model, optimizer=self.optimizer)  \n",
    "\n",
    "        # Restore variables on creation if a checkpoint exists.\n",
    "        self.checkpoint.restore(tf.train.latest_checkpoint(checkpoint_dir))\n",
    "    \n",
    "#     @tf.function\n",
    "    def compute_loss(self, logits, labels):\n",
    "        return tf.reduce_mean(tf.keras.losses.sparse_categorical_crossentropy(labels, logits, from_logits=True))\n",
    "\n",
    "\n",
    "    def compute_accuracy(self, logits, labels):\n",
    "        return tf.keras.metrics.sparse_categorical_accuracy(labels, logits)  # \n",
    "    \n",
    "    @tf.function\n",
    "    def train_step(self, images, labels):\n",
    "        # Record the operations used to compute the loss, so that the gradient\n",
    "        # of the loss with respect to the variables can be computed.\n",
    "        with tf.GradientTape() as tape:\n",
    "            logits = self.model(images, training=True)\n",
    "            loss = self.compute_loss(logits, labels)\n",
    "            accuracy = self.compute_accuracy(logits, labels)\n",
    "        grads = tape.gradient(loss, self.model.trainable_variables)\n",
    "        self.optimizer.apply_gradients(zip(grads, self.model.trainable_variables))\n",
    "        return loss, accuracy, logits\n",
    "\n",
    "    def training(self, train_dataset, test_dataset, epochs=1, log_freq=50):\n",
    "\n",
    "        for i in range(epochs):\n",
    "            train_start = time.time()\n",
    "            with self.train_summary_writer.as_default():\n",
    "                start = time.time()\n",
    "                # Metrics are stateful. They accumulate values and return a cumulative\n",
    "                # result when you call .result(). Clear accumulated values with .reset_states()\n",
    "                avg_loss = tf.keras.metrics.Mean('loss', dtype=tf.float32)  \n",
    "                avg_accuracy = tf.keras.metrics.Mean('accuracy', dtype=tf.float32)  \n",
    "\n",
    "                # Datasets can be iterated over like any other Python iterable.\n",
    "                for images, labels in train_dataset:\n",
    "                    loss, accuracy, logits = self.train_step(images, labels)\n",
    "                    avg_loss(loss)\n",
    "                    avg_accuracy(accuracy)\n",
    "\n",
    "                    if tf.equal(self.optimizer.iterations % log_freq, 0):\n",
    "                        summary_ops_v2.scalar('loss', avg_loss.result(), step=self.optimizer.iterations)\n",
    "                        summary_ops_v2.scalar('accuracy', avg_accuracy.result(), step=self.optimizer.iterations)\n",
    "                        \n",
    "                        rate = log_freq / (time.time() - start)\n",
    "                        print('Step #{}\\tLoss: {:0.6f} accuracy: {:0.2f}% ({} steps/sec)'.format(self.optimizer.iterations.numpy(), loss, (avg_accuracy.result() * 100), rate))\n",
    "                        avg_loss.reset_states()\n",
    "                        avg_accuracy.reset_states()\n",
    "                        start = time.time()\n",
    "\n",
    "            train_end = time.time()\n",
    "            print('\\nTrain time for epoch #{} ({} total steps): {}'.format(i + 1, self.optimizer.iterations.numpy(), train_end - train_start))\n",
    "            with self.test_summary_writer.as_default():\n",
    "                self.testing(test_dataset, self.optimizer.iterations)\n",
    "            self.checkpoint.save(self.checkpoint_prefix)\n",
    "        self.export_path = os.path.join(MODEL_DIR, 'export')\n",
    "        tf.saved_model.save(self.model, self.export_path)\n",
    "    \n",
    "    def testing(self, test_dataset, step_num):\n",
    "        \"\"\"Perform an evaluation of `model` on the examples from `dataset`.\"\"\"\n",
    "        avg_loss = tf.keras.metrics.Mean('loss', dtype=tf.float32)\n",
    "        avg_accuracy = tf.keras.metrics.Mean('accuracy', dtype=tf.float32)\n",
    "\n",
    "        for (images, labels) in test_dataset:\n",
    "            logits = self.model(images, training=False)\n",
    "            avg_loss(self.compute_loss(logits, labels))\n",
    "            avg_accuracy(self.compute_accuracy(logits, labels))\n",
    "\n",
    "        print('Model test set loss: {:0.4f} accuracy: {:0.2f}%'.format(avg_loss.result(), avg_accuracy.result() * 100))\n",
    "        summary_ops_v2.scalar('loss', avg_loss.result(), step=step_num)\n",
    "        summary_ops_v2.scalar('accuracy', avg_accuracy.result(), step=step_num)\n",
    "            \n",
    "    def evaluating(self, test_dataset):\n",
    "#         restored_model = tf.saved_model.restore(self.export_path)\n",
    "#         y_predict = restored_model(x_test)\n",
    "        avg_accuracy = tf.keras.metrics.Mean('accuracy', dtype=tf.float32)\n",
    "\n",
    "        for (images, labels) in test_dataset:\n",
    "            logits = self.model(images, training=False)\n",
    "            avg_accuracy(self.compute_accuracy(logits, labels))\n",
    "\n",
    "        print('Model accuracy: {:0.2f}%'.format(avg_accuracy.result() * 100))\n",
    "\n",
    "    def forward(self, xs):  \n",
    "        predictions = self.model(xs)\n",
    "        logits = tf.nn.softmax(predictions)\n",
    "\n",
    "        return logits\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [],
   "source": [
    "val_dataset = tf.data.Dataset.from_tensor_slices((valid_xs.astype(np.float32), valid_ys))\n",
    "val_dataset = val_dataset.batch(64)\n",
    "\n",
    "dataset = tf.data.Dataset.from_tensor_slices((train_xs.astype(np.float32), train_ys))\n",
    "dataset = dataset.batch(64)  # .shuffle(len(train_xs))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [],
   "source": [
    "test_dataset = tf.data.Dataset.from_tensor_slices((test_set.astype(np.float32), testset_y))\n",
    "test_dataset = test_dataset.batch(64)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 训练网络，跟之前没什么区别"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Step #50\tLoss: 2.993327 accuracy: 5.62% (3.469405740158293 steps/sec)\n",
      "Step #100\tLoss: 2.989202 accuracy: 5.84% (3.961076227813938 steps/sec)\n",
      "Step #150\tLoss: 2.937308 accuracy: 8.16% (4.267125483361401 steps/sec)\n",
      "Step #200\tLoss: 2.862231 accuracy: 9.72% (4.376610849618697 steps/sec)\n",
      "Step #250\tLoss: 2.841537 accuracy: 10.59% (4.251312743469853 steps/sec)\n",
      "Step #300\tLoss: 2.734112 accuracy: 13.22% (4.229191104927479 steps/sec)\n",
      "Step #350\tLoss: 2.673699 accuracy: 13.16% (4.306034308495572 steps/sec)\n",
      "Step #400\tLoss: 2.807307 accuracy: 13.62% (4.368079935609545 steps/sec)\n",
      "Step #450\tLoss: 2.764752 accuracy: 14.50% (4.318316995649359 steps/sec)\n",
      "\n",
      "Train time for epoch #1 (469 total steps): 113.01403522491455\n",
      "Model test set loss: 2.7539 accuracy: 16.08%\n"
     ]
    }
   ],
   "source": [
    "net = network()\n",
    "\n",
    "# net.training(dataset, val_dataset)\n",
    "net.training(val_dataset, test_dataset)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 测试集准确率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model accuracy: 16.08%\n"
     ]
    }
   ],
   "source": [
    "net.evaluating(test_dataset)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  },
  "widgets": {
   "state": {},
   "version": "1.1.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
